package com.zx._06_JVM.chapter_04_metrics;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.zx._06_JVM.chapter_04_metrics.model.GcMetrics;
import com.zx._06_JVM.chapter_04_metrics.model.JstatGcResult;
import com.zx._06_JVM.chapter_04_metrics.tool.JStat;
import com.zx.common.util.StreamUtil;
import java.util.List;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class GcMetricsAnaylizer {

    public static void main(String[] args) throws Exception {

        Thread t = new Thread(() -> {
            log.info("work start");
            int c = 1024 * 1024;
            while (!Thread.currentThread().isInterrupted()) {
                byte[][] b = new byte[c][1024];
                for (int i = 0; i < c; i++) {
                    b[i] = new byte[1024];
                }
            }
            log.info("work done");
        });
        t.start();

        // 获得gc监控数据
        String pid = JStat.getPid();
        List<JstatGcResult> gcResult = JStat.gc(pid, 5, 1);

        // 分析数据
        GcMetrics anaylizer = anaylizer(gcResult);

        log.info("anaylizer={}", JSONUtil.toJsonPrettyStr(anaylizer));

        log.info("扫描结束");
        // 终止线程
        t.interrupt();
    }

    public static GcMetrics anaylizer(List<JstatGcResult> gc) {
        JstatGcResult begin = gc.get(0);
        JstatGcResult end = gc.get(gc.size() - 1);
        int size = gc.size();

        // 运行总时长/单位秒
        long totalSecond = DateUtil.between(begin.getDate(), end.getDate(), DateUnit.SECOND);
        // 新生代
        double ygct = end.getYgct() - begin.getYgct();
        int ygc = end.getYgc() - begin.getYgc();

        // 老年代
        double fgct = end.getFgct() - begin.getFgct();
        int fgc = end.getFgc() - begin.getFgc();

        // gc总时长
        double gct = end.getGct() - begin.getGct();
        // gc总次数
        int gcc = ygc + fgc;

        GcMetrics metrics = new GcMetrics();

        // 1.GC吞吐量， 系统总运行时间=应用程序耗时+GC耗时
        metrics.setThroughput(JStat.percent(totalSecond - gct, totalSecond));

        // 2. 垃圾回收器负载=GC耗时/系统总运行时间
        metrics.setGcLoad(JStat.percent(gct, totalSecond));

        // 2.最大停顿时间，这个无法获得，只能通过分析日志获得

        // 4.垃圾回收频率
        metrics.setGcf(JStat.division(totalSecond, gcc));
        metrics.setYgct(JStat.division(totalSecond, ygc));
        metrics.setFgct(JStat.division(totalSecond, fgc));

        // 5. 堆使用率
        metrics.setMaxHeapUsed(StreamUtil.max(gc, JstatGcResult::getHeapp).getHeapp());
        metrics.setMinHeapUsed(StreamUtil.min(gc, JstatGcResult::getHeapp).getHeapp());
        metrics.setAvgHeapUsed(StreamUtil.avg(gc, JstatGcResult::getHeapp));

        metrics.setMaxHeapc(StreamUtil.max(gc, JstatGcResult::getHeapc).getHeapc() / 1024);
        metrics.setMinHeapc(StreamUtil.min(gc, JstatGcResult::getHeapc).getHeapc() / 1024);
        metrics.setAvgHeapc(StreamUtil.avg(gc, JstatGcResult::getHeapc) / 1024);

        metrics.setMaxSc(StreamUtil.max(gc, JstatGcResult::getS0c).getS0c() / 1024);
        metrics.setMinSc(StreamUtil.min(gc, JstatGcResult::getS0c).getS0c() / 1024);
        metrics.setAvgSc(StreamUtil.avg(gc, JstatGcResult::getS0c) / 1024);

        metrics.setMaxEc(StreamUtil.max(gc, JstatGcResult::getEc).getEc() / 1024);
        metrics.setMinEc(StreamUtil.min(gc, JstatGcResult::getEc).getEc() / 1024);
        metrics.setAvgEc(StreamUtil.avg(gc, JstatGcResult::getEc) / 1024);

        metrics.setMaxOc(StreamUtil.max(gc, JstatGcResult::getOc).getOc() / 1024);
        metrics.setMinOc(StreamUtil.min(gc, JstatGcResult::getOc).getOc() / 1024);
        metrics.setAvgOc(StreamUtil.avg(gc, JstatGcResult::getOc) / 1024);

        // 7.gc时间和次数
        metrics.setGct(gct);
        metrics.setGcc(gcc);
        metrics.setYgct(ygct);
        metrics.setYgc(ygc);
        metrics.setFgct(fgct);
        metrics.setFgc(fgc);
        return metrics;
    }


}
